home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / uucp-104.lha / uucp-1.04 / uux.c < prev    next >
C/C++ Source or Header  |  1993-02-13  |  38KB  |  1,503 lines

  1. /* uux.c
  2.    Prepare to execute a command on a remote system.
  3.  
  4.    Copyright (C) 1991, 1992 Ian Lance Taylor
  5.  
  6.    This file is part of the Taylor UUCP package.
  7.  
  8.    This program is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU General Public License as
  10.    published by the Free Software Foundation; either version 2 of the
  11.    License, or (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.    The author of the program may be contacted at ian@airs.com or
  23.    c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
  24.    */
  25.  
  26. #include "uucp.h"
  27.  
  28. #if USE_RCS_ID
  29. const char uux_rcsid[] = "$Id: uux.c,v 1.56 1993/01/21 05:11:34 ian Rel $";
  30. #endif
  31.  
  32. #include "uudefs.h"
  33. #include "uuconf.h"
  34. #include "system.h"
  35. #include "sysdep.h"
  36. #include "getopt.h"
  37.  
  38. #include <ctype.h>
  39. #include <errno.h>
  40.  
  41. /* These character lists should, perhaps, be in sysdep.h.  */
  42.  
  43. /* This is the list of shell metacharacters that we check for.  If one
  44.    of these is present, we request uuxqt to execute the command with
  45.    /bin/sh.  Otherwise we let it execute using execve.  */
  46.  
  47. #define ZSHELLCHARS "\"'`*?[;&()|<>\\$"
  48.  
  49. /* This is the list of word separators.  We break filename arguments
  50.    at these characters.  */
  51. #define ZSHELLSEPS ";&*|<> \t"
  52.  
  53. /* This is the list of word separators without the redirection
  54.    operators.  */
  55. #define ZSHELLNONREDIRSEPS ";&*| \t"
  56.  
  57. /* The program name.  */
  58. char abProgram[] = "uux";
  59.  
  60. /* The name of the execute file.  */
  61. const char *zXxqt_name;
  62.  
  63. /* The execute file we are creating.  */
  64. static FILE *eXxqt_file;
  65.  
  66. /* A list of commands to be spooled.  */
  67. static struct scmd *pasXcmds;
  68. static int cXcmds;
  69.  
  70. /* A file to close if we're forced to exit.  */
  71. static FILE *eXclose;
  72.  
  73. /* Local functions.  */
  74. static void uxusage P((void));
  75. static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2));
  76. static void uxadd_send_file P((const char *zfrom, const char *zto,
  77.                    const char *zoptions, const char *ztemp,
  78.                    const char *zforward,
  79.                    const struct uuconf_system *qxqtsys,
  80.                    const char *zxqtloc,
  81.                    int bgrade));
  82. static void uxcopy_stdin P((FILE *e));
  83. static void uxrecord_file P((const char *zfile));
  84. static void uxabort P((void));
  85.  
  86. /* Long getopt options.  */
  87. static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } };
  88.  
  89. /* The main routine.  */
  90.  
  91. int
  92. main (argc, argv)
  93.      int argc;
  94.      char **argv;
  95. {
  96.   /* -a: requestor address for status reports.  */
  97.   const char *zrequestor = NULL;
  98.   /* -b: if true, return standard input on error.  */
  99.   boolean fretstdin = FALSE;
  100.   /* -c,-C: if true, copy to spool directory.  */
  101.   boolean fcopy = FALSE;
  102.   /* -c: set if -c appears explicitly; if it and -l appear, then if the
  103.      link fails we don't copy the file.  */
  104.   boolean fdontcopy = FALSE;
  105.   /* -I: configuration file name.  */
  106.   const char *zconfig = NULL;
  107.   /* -j: output job id.  */
  108.   boolean fjobid = FALSE;
  109.   /* -g: job grade.  */
  110.   char bgrade = BDEFAULT_UUX_GRADE;
  111.   /* -l: link file to spool directory.  */
  112.   boolean flink = FALSE;
  113.   /* -n: do not notify upon command completion.  */
  114.   boolean fno_ack = FALSE;
  115.   /* -p: read standard input for command standard input.  */
  116.   boolean fread_stdin = FALSE;
  117.   /* -r: do not start uucico when finished.  */
  118.   boolean fuucico = TRUE;
  119.   /* -s: report status to named file.  */
  120.   const char *zstatus_file = NULL;
  121.   /* -W: only expand local file names.  */
  122.   boolean fexpand = TRUE;
  123.   /* -z: report status only on error.  */
  124.   boolean ferror_ack = FALSE;
  125.   int iopt;
  126.   pointer puuconf;
  127.   int iuuconf;
  128.   const char *zlocalname;
  129.   const char *zxqtloc;
  130.   int i;
  131.   size_t clen;
  132.   char *zargs;
  133.   char *zarg;
  134.   char *zcmd;
  135.   const char *zsys;
  136.   char *zexclam;
  137.   boolean fgetcwd;
  138.   const char *zuser;
  139.   struct uuconf_system sxqtsys;
  140.   boolean fxqtlocal;
  141.   char *zforward;
  142.   char **pzargs;
  143.   int calloc_args;
  144.   int cargs;
  145.   char abxqt_tname[CFILE_NAME_LEN];
  146.   char abxqt_xname[CFILE_NAME_LEN];
  147.   const char *zinput_from;
  148.   const char *zinput_to;
  149.   const char *zinput_temp;
  150.   boolean finputcopied;
  151.   char *zcall_system;
  152.   boolean fcall_any;
  153.   struct uuconf_system slocalsys;
  154.   boolean fneedshell;
  155.   char *zfullcmd;
  156.   boolean fexit;
  157.  
  158.   /* We need to be able to read a single - as an option, which getopt
  159.      won't do.  So that we can still use getopt, we run through the
  160.      options looking for an option "-"; if we find one we change it to
  161.      "-p", which is equivalent to "-".  */
  162.   for (i = 1; i < argc; i++)
  163.     {
  164.       if (argv[i][0] != '-')
  165.     break;
  166.       if (argv[i][1] == '\0')
  167.     argv[i] = zbufcpy ("-p");
  168.       else
  169.     {
  170.       const char *z;
  171.  
  172.       for (z = argv[i] + 1; *z != '\0'; z++)
  173.         {
  174.           /* If the option takes an argument, and the argument is
  175.          not appended, then skip the next argument.  */
  176.           if (*z == 'a' || *z == 'g' || *z == 'I'
  177.           || *z == 's' || *z == 'x')
  178.         {
  179.           if (z[1] == '\0')
  180.             i++;
  181.           break;
  182.         }
  183.         }
  184.     }
  185.     }
  186.  
  187.   /* The leading + in the getopt string means to stop processing
  188.      options as soon as a non-option argument is seen.  */
  189.   while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wx:z",
  190.                   asXlongopts, (int *) NULL)) != EOF)
  191.     {
  192.       switch (iopt)
  193.     {
  194.     case 'a':
  195.       /* Set requestor name: mail address to which status reports
  196.          should be sent.  */
  197.       zrequestor = optarg;
  198.       break;
  199.  
  200.     case 'b':
  201.       /* Return standard input on error.  */
  202.       fretstdin = TRUE;
  203.       break;
  204.  
  205.     case 'c':
  206.       /* Do not copy local files to spool directory.  */
  207.       fcopy = FALSE;
  208.       fdontcopy = TRUE;
  209.       break;
  210.  
  211.     case 'C':
  212.       /* Copy local files to spool directory.  */
  213.       fcopy = TRUE;
  214.       break;
  215.  
  216.     case 'I':
  217.       /* Configuration file name.  */ 
  218.       if (fsysdep_other_config (optarg))
  219.         zconfig = optarg;
  220.       break;
  221.  
  222.     case 'j':
  223.       /* Output jobid.  */
  224.       fjobid = TRUE;
  225.       break;
  226.  
  227.     case 'g':
  228.       /* Set job grade.  */
  229.       bgrade = optarg[0];
  230.       break;
  231.  
  232.     case 'l':
  233.       /* Link file to spool directory.  */
  234.       flink = TRUE;
  235.       break;
  236.  
  237.     case 'n':
  238.       /* Do not notify upon command completion.  */
  239.       fno_ack = TRUE;
  240.       break;
  241.  
  242.     case 'p':
  243.       /* Read standard input for command standard input.  */
  244.       fread_stdin = TRUE;
  245.       break;
  246.  
  247.     case 'r':
  248.       /* Do not start uucico when finished.  */
  249.       fuucico = FALSE;
  250.       break;
  251.  
  252.     case 's':
  253.       /* Report status to named file.  */
  254.       zstatus_file = optarg;
  255.       break;
  256.  
  257.     case 'W':
  258.       /* Only expand local file names.  */
  259.       fexpand = FALSE;
  260.       break;
  261.  
  262.     case 'x':
  263. #if DEBUG > 1
  264.       /* Set debugging level.  */
  265.       iDebug |= idebug_parse (optarg);
  266. #endif
  267.       break;
  268.  
  269.     case 'z':
  270.       /* Report status only on error.  */
  271.       ferror_ack = TRUE;
  272.       break;
  273.  
  274.     case 0:
  275.       /* Long option found and flag set.  */
  276.       break;
  277.  
  278.     default:
  279.       uxusage ();
  280.       break;
  281.     }
  282.     }
  283.  
  284.   if (! UUCONF_GRADE_LEGAL (bgrade))
  285.     {
  286.       ulog (LOG_ERROR, "Ignoring illegal grade");
  287.       bgrade = BDEFAULT_UUX_GRADE;
  288.     }
  289.  
  290.   if (optind == argc)
  291.     uxusage ();
  292.  
  293.   iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
  294.   if (iuuconf != UUCONF_SUCCESS)
  295.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  296.  
  297. #if DEBUG > 1
  298.   {
  299.     const char *zdebug;
  300.  
  301.     iuuconf = uuconf_debuglevel (puuconf, &zdebug);
  302.     if (iuuconf != UUCONF_SUCCESS)
  303.       ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  304.     if (zdebug != NULL)
  305.       iDebug |= idebug_parse (zdebug);
  306.   }
  307. #endif
  308.  
  309.   /* The command and files arguments could be quoted in any number of
  310.      ways, so we split them apart ourselves.  We do this before
  311.      calling usysdep_initialize because we want to set fgetcwd
  312.      correctly.  */
  313.   clen = 1;
  314.   for (i = optind; i < argc; i++)
  315.     clen += strlen (argv[i]) + 1;
  316.  
  317.   zargs = zbufalc (clen);
  318.   *zargs = '\0';
  319.   for (i = optind; i < argc; i++)
  320.     {
  321.       strcat (zargs, argv[i]);
  322.       strcat (zargs, " ");
  323.     }
  324.  
  325.   /* The first argument is the command to execute.  */
  326.   clen = strcspn (zargs, ZSHELLSEPS);
  327.   zcmd = zbufalc (clen + 1);
  328.   strncpy (zcmd, zargs, clen);
  329.   zcmd[clen] = '\0';
  330.   zargs += clen;
  331.  
  332.   /* Split the arguments out into an array.  We break the arguments
  333.      into alternating sequences of characters not in ZSHELLSEPS
  334.      and characters in ZSHELLSEPS.  We remove whitespace.  We
  335.      separate the redirection characters '>' and '<' into their
  336.      own arguments to make them easier to process below.  */
  337.   calloc_args = 10;
  338.   pzargs = (char **) xmalloc (calloc_args * sizeof (char *));
  339.   cargs = 0;
  340.  
  341.   for (zarg = strtok (zargs, " \t");
  342.        zarg != NULL;
  343.        zarg = strtok ((char *) NULL, " \t"))
  344.     {
  345.       while (*zarg != '\0')
  346.     {
  347.       if (cargs + 1 >= calloc_args)
  348.         {
  349.           calloc_args += 10;
  350.           pzargs = (char **) xrealloc ((pointer) pzargs,
  351.                        calloc_args * sizeof (char *));
  352.         }
  353.  
  354.       clen = strcspn (zarg, ZSHELLSEPS);
  355.       if (clen > 0)
  356.         {
  357.           pzargs[cargs] = zbufalc (clen + 1);
  358.           memcpy (pzargs[cargs], zarg, clen);
  359.           pzargs[cargs][clen] = '\0';
  360.           ++cargs;
  361.           zarg += clen;
  362.         }
  363.  
  364.       /* We deliberately separate '>' and '<' out.  */
  365.       if (*zarg != '\0')
  366.         {
  367.           clen = strspn (zarg, ZSHELLNONREDIRSEPS);
  368.           if (clen == 0)
  369.         clen = 1;
  370.           pzargs[cargs] = zbufalc (clen + 1);
  371.           memcpy (pzargs[cargs], zarg, clen);
  372.           pzargs[cargs][clen] = '\0';
  373.           ++cargs;
  374.           zarg += clen;
  375.         }
  376.     }
  377.     }
  378.  
  379.   /* Now look through the arguments to see if we are going to need the
  380.      current working directory.  We don't try to make a precise
  381.      determination, just a conservative one.  The basic idea is that
  382.      we don't want to get the cwd for 'foo!rmail - user' (note that we
  383.      don't examine the command itself).  */
  384.   fgetcwd = FALSE;
  385.   for (i = 0; i < cargs; i++)
  386.     {
  387.       if (pzargs[i][0] == '(')
  388.     continue;
  389.       zexclam = strrchr (pzargs[i], '!');
  390.       if (zexclam != NULL && fsysdep_needs_cwd (zexclam + 1))
  391.     {
  392.       fgetcwd = TRUE;
  393.       break;
  394.     }
  395.       if ((pzargs[i][0] == '<' || pzargs[i][0] == '>')
  396.       && i + 1 < cargs
  397.       && strchr (pzargs[i + 1], '!') == NULL
  398.       && fsysdep_needs_cwd (pzargs[i + 1]))
  399.     {
  400.       fgetcwd = TRUE;
  401.       break;
  402.     }
  403.     }
  404.  
  405. #ifdef SIGINT
  406.   usysdep_signal (SIGINT);
  407. #endif
  408. #ifdef SIGHUP
  409.   usysdep_signal (SIGHUP);
  410. #endif
  411. #ifdef SIGQUIT
  412.   usysdep_signal (SIGQUIT);
  413. #endif
  414. #ifdef SIGTERM
  415.   usysdep_signal (SIGTERM);
  416. #endif
  417. #ifdef SIGPIPE
  418.   usysdep_signal (SIGPIPE);
  419. #endif
  420.  
  421.   usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0));
  422.  
  423.   ulog_fatal_fn (uxabort);
  424.  
  425.   zuser = zsysdep_login_name ();
  426.  
  427.   /* Get the local system name.  */
  428.   iuuconf = uuconf_localname (puuconf, &zlocalname);
  429.   if (iuuconf == UUCONF_NOT_FOUND)
  430.     {
  431.       zlocalname = zsysdep_localname ();
  432.       if (zlocalname == NULL)
  433.     exit (EXIT_FAILURE);
  434.     }
  435.   else if (iuuconf != UUCONF_SUCCESS)
  436.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  437.  
  438.   /* Get the local system information.  */
  439.   iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys);
  440.   if (iuuconf != UUCONF_SUCCESS)
  441.     {
  442.       if (iuuconf != UUCONF_NOT_FOUND)
  443.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  444.       iuuconf = uuconf_system_local (puuconf, &slocalsys);
  445.       if (iuuconf != UUCONF_SUCCESS)
  446.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  447.     }
  448.  
  449.   /* Figure out which system the command is to be executed on.  Some
  450.      mailers apparently pass local!rmail, so we must explicitly check
  451.      for that.  */
  452.   zexclam = strchr (zcmd, '!');
  453.   while (zexclam != NULL)
  454.     {
  455.       *zexclam = '\0';
  456.       if (strcmp (zcmd, zlocalname) == 0)
  457.     ;
  458.       else if (slocalsys.uuconf_pzalias == NULL)
  459.     break;
  460.       else
  461.     {
  462.       char **pzal;
  463.  
  464.       for (pzal = slocalsys.uuconf_pzalias; *pzal != NULL; pzal++)
  465.         if (strcmp (zcmd, *pzal) == 0)
  466.           break;
  467.       if (*pzal == NULL)
  468.         break;
  469.     }
  470.       zcmd = zexclam + 1;
  471.       zexclam = strchr (zcmd, '!');
  472.     }
  473.   if (zexclam == NULL)
  474.     {
  475.       zsys = zlocalname;
  476.       fxqtlocal = TRUE;
  477.       zforward = NULL;
  478.     }
  479.   else
  480.     {
  481.       zsys = zcmd;
  482.       zcmd = zexclam + 1;
  483.       fxqtlocal = FALSE;
  484.  
  485.       /* See if we must forward this command through other systems
  486.      (e.g. uux a!b!cmd).  */
  487.       zexclam = strrchr (zcmd, '!');
  488.       if (zexclam == NULL)
  489.     zforward = NULL;
  490.       else
  491.     {
  492.       clen = zexclam - zcmd;
  493.       zforward = zbufalc (clen);
  494.       memcpy (zforward, zcmd, clen);
  495.       zforward[clen] = '\0';
  496.       zcmd = zexclam + 1;
  497.     }
  498.     }
  499.  
  500.   if (fxqtlocal)
  501.     sxqtsys = slocalsys;
  502.   else
  503.     {
  504.       iuuconf = uuconf_system_info (puuconf, zsys, &sxqtsys);
  505.       if (iuuconf != UUCONF_SUCCESS)
  506.     {
  507.       if (iuuconf != UUCONF_NOT_FOUND)
  508.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  509.       if (! funknown_system (puuconf, zsys, &sxqtsys))
  510.         ulog (LOG_FATAL, "%s: System not found", zsys);
  511.     }
  512.     }
  513.  
  514.   /* Get the local name the remote system know us as.  */
  515.   zxqtloc = sxqtsys.uuconf_zlocalname;
  516.   if (zxqtloc == NULL)
  517.     zxqtloc = zlocalname;
  518.  
  519.   /* We can send this as an E command if the execution is on a
  520.      different, directly connected, system and the only file used is
  521.      the standard input and comes from this system.  This is true of
  522.      the common cases of rmail and rnews.  We get an execute file name
  523.      here in case we need it.  */
  524.   if (fxqtlocal)
  525.     zXxqt_name = zsysdep_xqt_file_name ();
  526.   else
  527.     zXxqt_name = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, TRUE,
  528.                      abxqt_tname, (char *) NULL,
  529.                      abxqt_xname);
  530.   if (zXxqt_name == NULL)
  531.     uxabort ();
  532.  
  533.   uxrecord_file (zXxqt_name);
  534.  
  535.   /* Look through the arguments.  Any argument containing an
  536.      exclamation point character is interpreted as a file name, and is
  537.      sent to the appropriate system.  */
  538.   zinput_from = NULL;
  539.   zinput_to = NULL;
  540.   zinput_temp = NULL;
  541.   finputcopied = FALSE;
  542.   zcall_system = NULL;
  543.   fcall_any = FALSE;
  544.  
  545.   for (i = 0; i < cargs; i++)
  546.     {
  547.       const char *zsystem;
  548.       char *zfile;
  549.       char *zforw;
  550.       boolean finput, foutput;
  551.       boolean flocal, fonxqt;
  552.  
  553.       /* Check for a parenthesized argument; remove the parentheses
  554.      and otherwise ignore it (this is how an exclamation point is
  555.      quoted).  */
  556.       if (pzargs[i][0] == '(')
  557.     {
  558.       clen = strlen (pzargs[i]);
  559.       if (pzargs[i][clen - 1] != ')')
  560.         ulog (LOG_ERROR, "Mismatched parentheses");
  561.       else
  562.         pzargs[i][clen - 1] = '\0';
  563.       ++pzargs[i];
  564.       continue;
  565.     }
  566.  
  567.       /* Check whether we are doing a redirection.  */
  568.       finput = FALSE;
  569.       foutput = FALSE;
  570.       if (i + 1 < cargs)
  571.     {
  572.       if (pzargs[i][0] == '<')
  573.         finput = TRUE;
  574.       else if (pzargs[i][0] == '>')
  575.         foutput = TRUE;
  576.       if (finput || foutput)
  577.         {
  578.           pzargs[i] = NULL;
  579.           i++;
  580.         }
  581.     }
  582.  
  583.       zexclam = strchr (pzargs[i], '!');
  584.  
  585.       /* If there is no exclamation point and no redirection, this
  586.      argument is left untouched.  */
  587.       if (zexclam == NULL && ! finput && ! foutput)
  588.     continue;
  589.  
  590.       /* Get the system name and file name for this file.  */
  591.       if (zexclam == NULL)
  592.     {
  593.       zsystem = zlocalname;
  594.       zfile = pzargs[i];
  595.       flocal = TRUE;
  596.       zforw = NULL;
  597.     }
  598.       else
  599.     {
  600.       *zexclam = '\0';
  601.       zsystem = pzargs[i];
  602.       if (*zsystem != '\0')
  603.         flocal = FALSE;
  604.       else
  605.         {
  606.           zsystem = zlocalname;
  607.           flocal = TRUE;
  608.         }
  609.       zfile = zexclam + 1;
  610.       zexclam = strrchr (zfile, '!');
  611.       if (zexclam == NULL)
  612.         zforw = NULL;
  613.       else
  614.         {
  615.           if (flocal)
  616.         ulog (LOG_FATAL, "!%s: Can't figure out where to get file",
  617.               zfile);
  618.           *zexclam = '\0';
  619.           zforw = zfile;
  620.           zfile = zexclam + 1;
  621.         }
  622.     }
  623.  
  624.       /* Check if the file is already on the execution system.  */
  625.       if (flocal)
  626.     fonxqt = fxqtlocal;
  627.       else if (fxqtlocal)
  628.     fonxqt = FALSE;
  629.       else if (zforward == NULL ? zforw != NULL : zforw == NULL)
  630.     fonxqt = FALSE;
  631.       else if (zforward != NULL
  632.            && zforw != NULL
  633.            && strcmp (zforward, zforw) != 0)
  634.     fonxqt = FALSE;
  635.       else if (strcmp (zsystem, sxqtsys.uuconf_zname) == 0)
  636.     fonxqt = TRUE;
  637.       else if (sxqtsys.uuconf_pzalias == NULL)
  638.     fonxqt = FALSE;
  639.       else
  640.     {
  641.       char **pzal;
  642.  
  643.       fonxqt = FALSE;
  644.       for (pzal = sxqtsys.uuconf_pzalias; *pzal != NULL; pzal++)
  645.         {
  646.           if (strcmp (zsystem, *pzal) == 0)
  647.         {
  648.           fonxqt = TRUE;
  649.           break;
  650.         }
  651.         }
  652.     }
  653.  
  654.       /* Turn the file into an absolute path.  */
  655.       if (flocal)
  656.     zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir);
  657.       else if (fexpand)
  658.     zfile = zsysdep_add_cwd (zfile);
  659.       if (zfile == NULL)
  660.     uxabort ();
  661.  
  662.       /* Check for output redirection.  */
  663.       if (foutput)
  664.     {
  665.       if (flocal)
  666.         {
  667.           if (! fin_directory_list (zfile,
  668.                     sxqtsys.uuconf_pzremote_receive,
  669.                     sxqtsys.uuconf_zpubdir, TRUE,
  670.                     FALSE, (const char *) NULL))
  671.         ulog (LOG_FATAL, "Not permitted to create %s", zfile);
  672.         }
  673.  
  674.       /* There are various cases of output redirection.
  675.  
  676.          uux cmd >out: The command is executed on the local
  677.          system, and the output file is placed on the local
  678.          system (fonxqt is TRUE).
  679.  
  680.          uux cmd >a!out: The command is executed on the local
  681.          system, and the output file is sent to a.
  682.  
  683.          uux a!cmd >out: The command is executed on a, and the
  684.          output file is returned to the local system (flocal
  685.          is TRUE).
  686.  
  687.          uux a!cmd >a!out: The command is executed on a, and the
  688.          output file is left on a (fonxqt is TRUE).
  689.  
  690.          uux a!cmd >b!out: The command is executed on a, and the
  691.          output file is sent to b; traditionally, I believe
  692.          that b is relative to a, rather than to the local
  693.          system.  However, this essentially contradicts the
  694.          previous two cases, in which the output file is
  695.          relative to the local system.
  696.  
  697.          Now, the cases that we don't handle.
  698.  
  699.          uux cmd >a!b!out: The command is executed on the local
  700.          system, and the output file is sent to b via a.  This
  701.          requires the local uuxqt to support forwarding of the
  702.          output file.
  703.  
  704.          uux a!b!cmd >out: The command is executed on b, which is
  705.          reached via a.  Probably the output file is intended
  706.          for the local system, in which case the uuxqt on b
  707.          must support forwarding of the output file.
  708.  
  709.          uux a!b!cmd >c!out: Is c relative to b or to the local
  710.          system?  If it's relative to b this is easy to
  711.          handle.  Otherwise, we must arrange for the file to
  712.          be sent back to the local system and for the local
  713.          system to send it on to c.
  714.  
  715.          There are many variations of the last case.  It's not at
  716.          all clear to me how they should be handled.  */
  717.       if (zforward != NULL || zforw != NULL)
  718.         ulog (LOG_FATAL, "May not forward standard output");
  719.  
  720.       if (fonxqt)
  721.         uxadd_xqt_line ('O', zfile, (const char *) NULL);
  722.       else if (flocal)
  723.         uxadd_xqt_line ('O', zfile, zxqtloc);
  724.       else
  725.         uxadd_xqt_line ('O', zfile, zsystem);
  726.       pzargs[i] = NULL;
  727.       continue;
  728.     }
  729.  
  730.       if (finput)
  731.     {
  732.       if (fread_stdin)
  733.         ulog (LOG_FATAL, "Standard input specified twice");
  734.       pzargs[i] = NULL;
  735.     }
  736.  
  737.       if (flocal)
  738.     {
  739.       char *zuse;
  740.       char *zdata;
  741.       char abtname[CFILE_NAME_LEN];
  742.       char abdname[CFILE_NAME_LEN];
  743.  
  744.       /* It's a local file.  If requested by -C, copy the file to
  745.          the spool directory.  If requested by -l, link the file
  746.          to the spool directory; if the link fails, we copy the
  747.          file, unless -c was explictly used.  If the execution is
  748.          occurring on the local system, we force the copy as well,
  749.          because otherwise we would have to have some way to tell
  750.          uuxqt not to move the file.  If the file is being shipped
  751.          to another system, we must set up a transfer request.
  752.          First make sure the user has legitimate access, since we
  753.          are running setuid.  */
  754.       if (! fsysdep_access (zfile))
  755.         uxabort ();
  756.  
  757.       zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE,
  758.                       abtname, abdname, (char *) NULL);
  759.       if (zdata == NULL)
  760.         uxabort ();
  761.  
  762.       if (fcopy || flink || fxqtlocal)
  763.         {
  764.           boolean fdid;
  765.  
  766.           uxrecord_file (zdata);
  767.  
  768.           fdid = FALSE;
  769.           if (flink)
  770.         {
  771.           boolean fworked;
  772.  
  773.           if (! fsysdep_link (zfile, zdata, &fworked))
  774.             uxabort ();
  775.  
  776.           if (fworked)
  777.             fdid = TRUE;
  778.           else if (fdontcopy)
  779.             ulog (LOG_FATAL, "%s: Can't link to spool directory",
  780.               zfile);
  781.         }
  782.  
  783.           if (! fdid)
  784.         {
  785.           openfile_t efile;
  786.  
  787.           efile = esysdep_user_fopen (zfile, TRUE, TRUE);
  788.           if (! ffileisopen (efile))
  789.             uxabort ();
  790.           if (! fcopy_open_file (efile, zdata, FALSE, TRUE))
  791.             uxabort ();
  792.           (void) ffileclose (efile);
  793.         }
  794.  
  795.           zuse = abtname;
  796.         }
  797.       else
  798.         {
  799.           /* We don't actually use the spool file name, but we
  800.          need a name to use as the destination.  */
  801.           ubuffree (zdata);
  802.           /* Make sure the daemon can access the file.  */
  803.           if (! fsysdep_daemon_access (zfile))
  804.         uxabort ();
  805.           if (! fin_directory_list (zfile, sxqtsys.uuconf_pzlocal_send,
  806.                     sxqtsys.uuconf_zpubdir, TRUE,
  807.                     TRUE, zuser))
  808.         ulog (LOG_FATAL, "Not permitted to send from %s",
  809.               zfile);
  810.  
  811.           zuse = zfile;
  812.         }
  813.  
  814.       if (fxqtlocal)
  815.         {
  816.           if (finput)
  817.         uxadd_xqt_line ('I', zuse, (char *) NULL);
  818.           else
  819.         pzargs[i] = zuse;
  820.         }
  821.       else
  822.         {
  823.           finputcopied = fcopy || flink;
  824.  
  825.           if (finput)
  826.         {
  827.           zinput_from = zuse;
  828.           zinput_to = zbufcpy (abdname);
  829.           zinput_temp = zbufcpy (abtname);
  830.         }
  831.           else
  832.         {
  833.           char *zbase;
  834.  
  835.           uxadd_send_file (zuse, abdname,
  836.                    finputcopied ? "C" : "c",
  837.                    abtname, zforward, &sxqtsys,
  838.                    zxqtloc, bgrade);
  839.           zbase = zsysdep_base_name (zfile);
  840.           if (zbase == NULL)
  841.             uxabort ();
  842.           uxadd_xqt_line ('F', abdname, zbase);
  843.           pzargs[i] = zbase;
  844.         }
  845.         }
  846.     }
  847.       else if (fonxqt)
  848.     {
  849.       /* The file is already on the system where the command is to
  850.          be executed.  */
  851.       if (finput)
  852.         uxadd_xqt_line ('I', zfile, (const char *) NULL);
  853.       else
  854.         pzargs[i] = zfile;
  855.     }
  856.       else
  857.     {
  858.       struct uuconf_system sfromsys;
  859.       char abtname[CFILE_NAME_LEN];
  860.       struct scmd s;
  861.       char *zjobid;
  862.  
  863.       /* We need to request a remote file.  */
  864.       iuuconf = uuconf_system_info (puuconf, zsystem, &sfromsys);
  865.       if (iuuconf != UUCONF_SUCCESS)
  866.         {
  867.           if (iuuconf != UUCONF_NOT_FOUND)
  868.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  869.           if (! funknown_system (puuconf, zsystem, &sfromsys))
  870.         ulog (LOG_FATAL, "%s: System not found", zsystem);
  871.         }
  872.  
  873.       if (fonxqt)
  874.         {
  875.           /* The file is already on the system where the command is to
  876.          be executed.  */
  877.           if (finput)
  878.         uxadd_xqt_line ('I', zfile, (const char *) NULL);
  879.           else
  880.         pzargs[i] = zfile;
  881.         }
  882.       else
  883.         {
  884.           char *zdata;
  885.  
  886.           if (! sfromsys.uuconf_fcall_transfer
  887.           && ! sfromsys.uuconf_fcalled_transfer)
  888.         ulog (LOG_FATAL,
  889.               "Not permitted to transfer files to or from %s",
  890.               sfromsys.uuconf_zname);
  891.  
  892.           if (zforw != NULL)
  893.         {
  894.           /* This is ``uux cmd a!b!file''.  To make this work,
  895.              we would have to be able to set up a request to a
  896.              to fetch file from b and send it to us.  But it
  897.              turns out that that will not work, because when a
  898.              sends us the file we will put it in a's spool
  899.              directory, not the local system spool directory.
  900.              So we won't have any way to find it.  This is not
  901.              a conceptual problem, and it could doubtless be
  902.              solved.  Please feel free to solve it and send me
  903.              the solution.  */
  904.           ulog (LOG_FATAL, "File forwarding not supported");
  905.         }
  906.  
  907.           /* We must request the file from the remote system to
  908.          this one.  */
  909.           zdata = zsysdep_data_file_name (&slocalsys, zxqtloc, bgrade,
  910.                           FALSE, abtname, (char *) NULL,
  911.                           (char *) NULL);
  912.           if (zdata == NULL)
  913.         uxabort ();
  914.           ubuffree (zdata);
  915.  
  916.           /* Request the file.  The special option '9' is a signal
  917.          to uucico that it's OK to receive a file into the
  918.          spool directory; normally such requests are rejected.
  919.          This privilege is easy to abuse.  */
  920.           s.bcmd = 'R';
  921.           s.pseq = NULL;
  922.           s.zfrom = zfile;
  923.           s.zto = zbufcpy (abtname);
  924.           s.zuser = zuser;
  925.           s.zoptions = "9";
  926.           s.ztemp = "";
  927.           s.imode = 0600;
  928.           s.znotify = "";
  929.           s.cbytes = -1;
  930.           s.zcmd = NULL;
  931.           s.ipos = 0;
  932.  
  933.           zjobid = zsysdep_spool_commands (&sfromsys, bgrade, 1, &s);
  934.           if (zjobid == NULL)
  935.         uxabort ();
  936.  
  937.           if (fjobid)
  938.         printf ("%s\n", zjobid);
  939.  
  940.           ubuffree (zjobid);
  941.  
  942.           if (fcall_any)
  943.         {
  944.           ubuffree (zcall_system);
  945.           zcall_system = NULL;
  946.         }
  947.           else
  948.         {
  949.           fcall_any = TRUE;
  950.           zcall_system = zbufcpy (sfromsys.uuconf_zname);
  951.         }
  952.  
  953.           if (fxqtlocal)
  954.         {
  955.           /* Tell the command execution to wait until the file
  956.              has been received, and tell it the real file
  957.              name.  */
  958.           if (finput)
  959.             {
  960.               uxadd_xqt_line ('F', abtname, (char *) NULL);
  961.               uxadd_xqt_line ('I', abtname, (char *) NULL);
  962.             }
  963.           else
  964.             {
  965.               char *zbase;
  966.  
  967.               zbase = zsysdep_base_name (zfile);
  968.               if (zbase == NULL)
  969.             uxabort ();
  970.               uxadd_xqt_line ('F', abtname, zbase);
  971.               pzargs[i] = zbase;
  972.             }
  973.         }
  974.           else
  975.         {
  976.           char abxtname[CFILE_NAME_LEN];
  977.           char *zbase;
  978.           char *zxqt;
  979.           FILE *e;
  980.  
  981.           /* Now we must arrange to forward the file on to the
  982.              execution system.  We need to get a name to give
  983.              the file on the execution system (abxtname).  */
  984.           zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc,
  985.                           bgrade, TRUE, abxtname,
  986.                           (char *) NULL,
  987.                           (char *) NULL);
  988.           if (zdata == NULL)
  989.             uxabort ();
  990.           ubuffree (zdata);
  991.  
  992.           zbase = zsysdep_base_name (zfile);
  993.           if (zbase == NULL)
  994.             uxabort ();
  995.  
  996.           zxqt = zsysdep_xqt_file_name ();
  997.           if (zxqt == NULL)
  998.             uxabort ();
  999.           e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
  1000.           if (e == NULL)
  1001.             uxabort ();
  1002.           uxrecord_file (zxqt);
  1003.  
  1004.           fprintf (e, "U %s %s\n", zsysdep_login_name (),
  1005.                zlocalname);
  1006.           fprintf (e, "F %s %s\n", abtname, zbase);
  1007.           fprintf (e, "C uucp -C -W -d -g %c %s %s!", bgrade,
  1008.                zbase, sxqtsys.uuconf_zname);
  1009.           if (zforward != NULL)
  1010.             fprintf (e, "%s!", zforward);
  1011.           fprintf (e, "%s\n", abxtname);
  1012.  
  1013.           if (fclose (e) != 0)
  1014.             ulog (LOG_FATAL, "fclose: %s", strerror (errno));
  1015.  
  1016.           if (finput)
  1017.             {
  1018.               uxadd_xqt_line ('F', abxtname, (char *) NULL);
  1019.               uxadd_xqt_line ('I', abxtname, (char *) NULL);
  1020.               ubuffree (zbase);
  1021.             }
  1022.           else
  1023.             {
  1024.               uxadd_xqt_line ('F', abxtname, zbase);
  1025.               pzargs[i] = zbase;
  1026.             }
  1027.         }
  1028.         }
  1029.  
  1030.       (void) uuconf_system_free (puuconf, &sfromsys);
  1031.     }
  1032.     }
  1033.  
  1034.   /* If standard input is to be read from the stdin of uux, we read it
  1035.      here into a temporary file and send it to the execute system.  */
  1036.   if (fread_stdin)
  1037.     {
  1038.       char *zdata;
  1039.       char abtname[CFILE_NAME_LEN];
  1040.       char abdname[CFILE_NAME_LEN];
  1041.       FILE *e;
  1042.  
  1043.       zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE,
  1044.                       abtname, abdname, (char *) NULL);
  1045.       if (zdata == NULL)
  1046.     uxabort ();
  1047.  
  1048.       e = esysdep_fopen (zdata, FALSE, FALSE, TRUE);
  1049.       if (e == NULL)
  1050.     uxabort ();
  1051.  
  1052.       eXclose = e;
  1053.       uxrecord_file (zdata);
  1054.  
  1055.       uxcopy_stdin (e);
  1056.  
  1057.       eXclose = NULL;
  1058.       if (fclose (e) != 0)
  1059.     ulog (LOG_FATAL, "fclose: %s", strerror (errno));
  1060.  
  1061.       if (fxqtlocal)
  1062.     uxadd_xqt_line ('I', abtname, (const char *) NULL);
  1063.       else
  1064.     {
  1065.       zinput_from = zbufcpy (abtname);
  1066.       zinput_to = zbufcpy (abdname);
  1067.       zinput_temp = zinput_from;
  1068.       finputcopied = TRUE;
  1069.     }
  1070.     }
  1071.  
  1072.   /* If we are returning standard input, or we're putting the status
  1073.      in a file, we can't use an E command.  */
  1074.   if (fretstdin)
  1075.     uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL);
  1076.  
  1077.   if (zstatus_file != NULL)
  1078.     uxadd_xqt_line ('M', zstatus_file, (const char *) NULL);
  1079.  
  1080.   /* Get the complete command line, and decide whether the command
  1081.      needs to be executed by the shell.  */
  1082.   fneedshell = FALSE;
  1083.  
  1084.   if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0')
  1085.     fneedshell = TRUE;
  1086.  
  1087.   clen = strlen (zcmd) + 1;
  1088.   for (i = 0; i < cargs; i++)
  1089.     {
  1090.       if (pzargs[i] != NULL)
  1091.     {
  1092.       clen += strlen (pzargs[i]) + 1;
  1093.       if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0')
  1094.         fneedshell = TRUE;
  1095.     }
  1096.     }
  1097.  
  1098.   zfullcmd = zbufalc (clen);
  1099.  
  1100.   strcpy (zfullcmd, zcmd);
  1101.   for (i = 0; i < cargs; i++)
  1102.     {
  1103.       if (pzargs[i] != NULL)
  1104.     {
  1105.       strcat (zfullcmd, " ");
  1106.       strcat (zfullcmd, pzargs[i]);
  1107.     }
  1108.     }
  1109.  
  1110.   /* If we haven't written anything to the execution file yet, and we
  1111.      have a standard input file, and we're not forwarding, then every
  1112.      other option can be handled in an E command.  */
  1113.   if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL)
  1114.     {
  1115.       struct scmd s;
  1116.       char aboptions[10];
  1117.       char *zoptions;
  1118.  
  1119.       /* Set up an E command.  */
  1120.       s.bcmd = 'E';
  1121.       s.pseq = NULL;
  1122.       s.zuser = zuser;
  1123.       s.zfrom = zinput_from;
  1124.       s.zto = zinput_to;
  1125.       s.zoptions = aboptions;
  1126.       zoptions = aboptions;
  1127.       *zoptions++ = finputcopied ? 'C' : 'c';
  1128.       if (fno_ack)
  1129.     *zoptions++ = 'N';
  1130.       if (ferror_ack)
  1131.     *zoptions++ = 'Z';
  1132.       if (zrequestor != NULL)
  1133.     *zoptions++ = 'R';
  1134.       if (fneedshell)
  1135.     *zoptions++ = 'e';
  1136.       *zoptions = '\0';
  1137.       s.ztemp = zinput_temp;
  1138.       s.imode = 0666;
  1139.       if (zrequestor == NULL)
  1140.     zrequestor = "\"\"";
  1141.       s.znotify = zrequestor;
  1142.       s.cbytes = -1;
  1143.       s.zcmd = zfullcmd;
  1144.       s.ipos = 0;
  1145.       
  1146.       ++cXcmds;
  1147.       pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
  1148.                        cXcmds * sizeof (struct scmd));
  1149.       pasXcmds[cXcmds - 1] = s;
  1150.     }
  1151.   else
  1152.     {
  1153.       /* Finish up the execute file.  */
  1154.       uxadd_xqt_line ('U', zuser, zxqtloc);
  1155.       if (zinput_from != NULL)
  1156.     {
  1157.       uxadd_xqt_line ('F', zinput_to, (char *) NULL);
  1158.       uxadd_xqt_line ('I', zinput_to, (char *) NULL);
  1159.       uxadd_send_file (zinput_from, zinput_to,
  1160.                finputcopied ? "C" : "c",
  1161.                zinput_temp, zforward, &sxqtsys, zxqtloc,
  1162.                bgrade);
  1163.     }
  1164.       if (fno_ack)
  1165.     uxadd_xqt_line ('N', (const char *) NULL, (const char *) NULL);
  1166.       if (ferror_ack)
  1167.     uxadd_xqt_line ('Z', (const char *) NULL, (const char *) NULL);
  1168.       if (zrequestor != NULL)
  1169.     uxadd_xqt_line ('R', zrequestor, (const char *) NULL);
  1170.       if (fneedshell)
  1171.     uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL);
  1172.       uxadd_xqt_line ('C', zfullcmd, (const char *) NULL);
  1173.       if (fclose (eXxqt_file) != 0)
  1174.     ulog (LOG_FATAL, "fclose: %s", strerror (errno));
  1175.       eXxqt_file = NULL;
  1176.  
  1177.       /* If the execution is to occur on another system, we must now
  1178.      arrange to copy the execute file to this system.  */
  1179.       if (! fxqtlocal)
  1180.     uxadd_send_file (abxqt_tname, abxqt_xname, "C", abxqt_tname,
  1181.              zforward, &sxqtsys, zxqtloc, bgrade);
  1182.     }
  1183.  
  1184.   /* If we got a signal, get out before spooling anything.  */
  1185.   if (FGOT_SIGNAL ())
  1186.     uxabort ();
  1187.  
  1188.   /* From here on in, it's too late.  We don't call uxabort.  */
  1189.   if (cXcmds > 0)
  1190.     {
  1191.       char *zjobid;
  1192.  
  1193.       if (! sxqtsys.uuconf_fcall_transfer
  1194.       && ! sxqtsys.uuconf_fcalled_transfer)
  1195.     ulog (LOG_FATAL, "Not permitted to transfer files to or from %s",
  1196.           sxqtsys.uuconf_zname);
  1197.  
  1198.       zjobid = zsysdep_spool_commands (&sxqtsys, bgrade, cXcmds, pasXcmds);
  1199.       if (zjobid == NULL)
  1200.     {
  1201.       ulog_close ();
  1202.       usysdep_exit (FALSE);
  1203.     }
  1204.  
  1205.       if (fjobid)
  1206.     printf ("%s\n", zjobid);
  1207.  
  1208.       ubuffree (zjobid);
  1209.  
  1210.       if (fcall_any)
  1211.     {
  1212.       ubuffree (zcall_system);
  1213.       zcall_system = NULL;
  1214.     }
  1215.       else
  1216.     {
  1217.       fcall_any = TRUE;
  1218.       zcall_system = zbufcpy (sxqtsys.uuconf_zname);
  1219.     }
  1220.     }
  1221.  
  1222.   /* If all that worked, make a log file entry.  All log file reports
  1223.      up to this point went to stderr.  */
  1224.   ulog_to_file (puuconf, TRUE);
  1225.   ulog_system (sxqtsys.uuconf_zname);
  1226.   ulog_user (zuser);
  1227.  
  1228.   ulog (LOG_NORMAL, "Queuing %s", zfullcmd);
  1229.  
  1230.   ulog_close ();
  1231.  
  1232.   if (! fuucico)
  1233.     fexit = TRUE;
  1234.   else
  1235.     {
  1236.       if (zcall_system != NULL)
  1237.     fexit = fsysdep_run ("uucico", "-s", zcall_system);
  1238.       else if (fcall_any)
  1239.     fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL);
  1240.       else
  1241.     fexit = TRUE;
  1242.     }
  1243.  
  1244.   usysdep_exit (fexit);
  1245.  
  1246.   /* Avoid error about not returning a value.  */
  1247.   return 0;
  1248. }
  1249.  
  1250. /* Report command usage.  */
  1251.  
  1252. static void
  1253. uxusage ()
  1254. {
  1255.   fprintf (stderr,
  1256.        "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
  1257.        VERSION);
  1258.   fprintf (stderr,
  1259.        "Usage: uux [options] [-] command\n");
  1260.   fprintf (stderr,
  1261.        " -,-p: Read standard input for standard input of command\n");
  1262.   fprintf (stderr,
  1263.        " -c: Do not copy local files to spool directory (default)\n");
  1264.   fprintf (stderr,
  1265.        " -C: Copy local files to spool directory\n");
  1266.   fprintf (stderr,
  1267.        " -l: link local files to spool directory\n");
  1268.   fprintf (stderr,
  1269.        " -g grade: Set job grade (must be alphabetic)\n");
  1270.   fprintf (stderr,
  1271.        " -n: Do not report completion status\n");
  1272.   fprintf (stderr,
  1273.        " -z: Report completion status only on error\n");
  1274.   fprintf (stderr,
  1275.        " -r: Do not start uucico daemon\n");
  1276.   fprintf (stderr,
  1277.        " -a address: Address to mail status report to\n");
  1278.   fprintf (stderr,
  1279.        " -b: Return standard input with status report\n");
  1280.   fprintf (stderr,
  1281.        " -s file: Report completion status to file\n");
  1282.   fprintf (stderr,
  1283.        " -j: Report job id\n");
  1284.   fprintf (stderr,
  1285.        " -x debug: Set debugging level\n");
  1286. #if HAVE_TAYLOR_CONFIG
  1287.   fprintf (stderr,
  1288.        " -I file: Set configuration file to use\n");
  1289. #endif /* HAVE_TAYLOR_CONFIG */
  1290.   exit (EXIT_FAILURE);
  1291. }
  1292.  
  1293. /* Add a line to the execute file.  */
  1294.  
  1295. static void
  1296. uxadd_xqt_line (bchar, z1, z2)
  1297.      int bchar;
  1298.      const char *z1;
  1299.      const char *z2;
  1300. {
  1301.   if (eXxqt_file == NULL)
  1302.     {
  1303.       eXxqt_file = esysdep_fopen (zXxqt_name, FALSE, FALSE, TRUE);
  1304.       if (eXxqt_file == NULL)
  1305.     uxabort ();
  1306.     }
  1307.  
  1308.   if (z1 == NULL)
  1309.     fprintf (eXxqt_file, "%c\n", bchar);
  1310.   else if (z2 == NULL)
  1311.     fprintf (eXxqt_file, "%c %s\n", bchar, z1);
  1312.   else
  1313.     fprintf (eXxqt_file, "%c %s %s\n", bchar, z1, z2);
  1314. }
  1315.  
  1316. /* Add a file to be sent to the execute system.  */
  1317.  
  1318. static void
  1319. uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc,
  1320.          bgrade)
  1321.      const char *zfrom;
  1322.      const char *zto;
  1323.      const char *zoptions;
  1324.      const char *ztemp;
  1325.      const char *zforward;
  1326.      const struct uuconf_system *qxqtsys;
  1327.      const char *zxqtloc;
  1328.      int bgrade;
  1329. {
  1330.   struct scmd s;
  1331.  
  1332.   if (zforward != NULL)
  1333.     {
  1334.       char *zbase;
  1335.       char *zxqt;
  1336.       char abtname[CFILE_NAME_LEN];
  1337.       char abdname[CFILE_NAME_LEN];
  1338.       char abxname[CFILE_NAME_LEN];
  1339.       FILE *e;
  1340.  
  1341.       /* We want to forward this file through the first execution
  1342.      system to other systems.  We set up a remote execution of
  1343.      uucp to forward the file.  */
  1344.       zbase = zsysdep_base_name (zfrom);
  1345.       if (zbase == NULL)
  1346.     uxabort ();
  1347.  
  1348.       zxqt = zsysdep_data_file_name (qxqtsys, zxqtloc, bgrade, TRUE, abtname,
  1349.                      abdname, abxname);
  1350.       if (zxqt == NULL)
  1351.     uxabort ();
  1352.       e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
  1353.       if (e == NULL)
  1354.     uxabort ();
  1355.       uxrecord_file (zxqt);
  1356.  
  1357.       fprintf (e, "U %s %s\n", zsysdep_login_name (), zxqtloc);
  1358.       fprintf (e, "F %s %s\n", abdname, zbase);
  1359.       fprintf (e, "C uucp -C -W -d -g %c %s %s!%s\n",
  1360.            bgrade, zbase, zforward, zto);
  1361.  
  1362.       ubuffree (zbase);
  1363.  
  1364.       if (fclose (e) != 0)
  1365.     ulog (LOG_FATAL, "fclose: %s", strerror (errno));
  1366.  
  1367.       /* Send the execution file.  */
  1368.       s.bcmd = 'S';
  1369.       s.pseq = NULL;
  1370.       s.zfrom = zbufcpy (abtname);
  1371.       s.zto = zbufcpy (abxname);
  1372.       s.zuser = zsysdep_login_name ();
  1373.       s.zoptions = "C";
  1374.       s.ztemp = s.zfrom;
  1375.       s.imode = 0666;
  1376.       s.znotify = NULL;
  1377.       s.cbytes = -1;
  1378.       s.zcmd = NULL;
  1379.       s.ipos = 0;
  1380.  
  1381.       ++cXcmds;
  1382.       pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
  1383.                        cXcmds * sizeof (struct scmd));
  1384.       pasXcmds[cXcmds - 1] = s;
  1385.  
  1386.       /* Send the data file to abdname where the execution file will
  1387.      expect it.  */
  1388.       zto = abdname;
  1389.     }
  1390.  
  1391.   s.bcmd = 'S';
  1392.   s.pseq = NULL;
  1393.   s.zfrom = zbufcpy (zfrom);
  1394.   s.zto = zbufcpy (zto);
  1395.   s.zuser = zsysdep_login_name ();
  1396.   s.zoptions = zbufcpy (zoptions);
  1397.   s.ztemp = zbufcpy (ztemp);
  1398.   s.imode = 0666;
  1399.   s.znotify = "";
  1400.   s.cbytes = -1;
  1401.   s.zcmd = NULL;
  1402.   s.ipos = 0;
  1403.  
  1404.   ++cXcmds;
  1405.   pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
  1406.                        cXcmds * sizeof (struct scmd));
  1407.   pasXcmds[cXcmds - 1] = s;
  1408. }
  1409.  
  1410. /* Copy stdin to a file.  This is a separate function because it may
  1411.    call setjmp.  */
  1412.  
  1413. static void
  1414. uxcopy_stdin (e)
  1415.      FILE *e;
  1416. {
  1417.   CATCH_PROTECT size_t cread;
  1418.   char ab[1024];
  1419.  
  1420.   do
  1421.     {
  1422.       size_t cwrite;
  1423.  
  1424.       /* I want to use fread here, but there is a bug in some versions
  1425.      of SVR4 which causes fread to return less than a complete
  1426.      buffer even if EOF has not been reached.  This is not online
  1427.      time, so speed is not critical, but it's still quite annoying
  1428.      to have to use an inefficient algorithm.  */
  1429.       cread = 0;
  1430.       if (fsysdep_catch ())
  1431.     {
  1432.       usysdep_start_catch ();
  1433.  
  1434.       while (cread < sizeof (ab))
  1435.         {
  1436.           int b;
  1437.  
  1438.           if (FGOT_SIGNAL ())
  1439.         uxabort ();
  1440.  
  1441.           /* There's an unimportant race here.  If the user hits
  1442.          ^C between the FGOT_SIGNAL we just did and the time
  1443.          we enter getchar, we won't know about the signal
  1444.          (unless we're doing a longjmp, but we normally
  1445.          aren't).  It's not a big problem, because the user
  1446.          can just hit ^C again.  */
  1447.           b = getchar ();
  1448.           if (b == EOF)
  1449.         break;
  1450.           ab[cread] = b;
  1451.           ++cread;
  1452.         }
  1453.     }
  1454.  
  1455.       usysdep_end_catch ();
  1456.  
  1457.       if (FGOT_SIGNAL ())
  1458.     uxabort ();
  1459.  
  1460.       if (cread > 0)
  1461.     {
  1462.       cwrite = fwrite (ab, sizeof (char), cread, e);
  1463.       if (cwrite != cread)
  1464.         ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d",
  1465.           (int) cwrite, (int) cread);
  1466.     }
  1467.     }
  1468.   while (cread == sizeof ab);
  1469. }
  1470.  
  1471. /* Keep track of all files we have created so that we can delete them
  1472.    if we get a signal.  The argument will be on the heap.  */
  1473.  
  1474. static int cXfiles;
  1475. static const char **pXaz;
  1476.  
  1477. static void
  1478. uxrecord_file (zfile)
  1479.      const char *zfile;
  1480. {
  1481.   pXaz = (const char **) xrealloc ((pointer) pXaz,
  1482.                    (cXfiles + 1) * sizeof (const char *));
  1483.   pXaz[cXfiles] = zfile;
  1484.   ++cXfiles;
  1485. }
  1486.  
  1487. /* Delete all the files we have recorded and exit.  */
  1488.  
  1489. static void
  1490. uxabort ()
  1491. {
  1492.   int i;
  1493.  
  1494.   if (eXxqt_file != NULL)
  1495.     (void) fclose (eXxqt_file);
  1496.   if (eXclose != NULL)
  1497.     (void) fclose (eXclose);
  1498.   for (i = 0; i < cXfiles; i++)
  1499.     (void) remove (pXaz[i]);
  1500.   ulog_close ();
  1501.   usysdep_exit (FALSE);
  1502. }
  1503.